Redis 复制

在分布式系统中为了解决单点问题, 通常会把数据复制多个副本部署到其他机器, 满足故障恢复和负载均衡等需求。 Redis也是如此, 它提供了复制功能, 实现了相同数据的多个Redis副本。 复制功能是高可用Redis的基础。

介绍

  • Redis 使用异步复制。 从 Redis 2.8 开始, 从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。

  • 一个主服务器可以有多个从服务器。

  • 不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构。

  • 复制功能不会阻塞主服务器: 即使有一个或多个从服务器正在进行初次同步, 主服务器也可以继续处理命令请求。

  • 复制功能也不会阻塞从服务器: 只要在 redis.conf 文件中进行了相应的设置, 即使从服务器正在进行初次同步, 服务器也可以使用旧版本的数据集来处理命令查询。不过, 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 连接请求会被阻塞。

    还可以配置从服务器, 让它在与主服务器之间的连接断开时, 向客户端发送一个错误。

  • 复制功能可以单纯地用于数据冗余(data redundancy), 也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 比如说, 繁重的 SORT 命令可以交给附属节点去运行。

  • 可以通过复制功能来让主服务器免于执行持久化操作: 只要关闭主服务器的持久化功能, 然后由从服务器去执行持久化操作即可。

Redis 使用复制功能非常容易,只需要在从数据库的配置文件中加入slaveof 主库地址 主库端口即可,主库无需进行任何配置.

默认情况下,从数据库是只读的.

原理

复制过程

当一个从数据库启动后,会向主数据库发送SYNC命令,同时主数据库收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程)并在保存快照期间将收到的命令缓存起来,当快照完成后,Redis 会将快照文件和所有缓存的命令一起发给从数据库.从数据库收到后,会载入快照文件并执行收到的缓存命令,以上过程成为复制初始化.复制初始化结束后,主数据库每当收到写命令时就会将命令同步给从数据库.从而保障主从数据库数据库一致.

当主从数据库连接断开重连后,2.6之前的版本会进行复制初始化这样效率就很低,所以2.8后的版本支持了有条件的增量数据传输.从库重新连接上主库后,只需要将断线期间执行的命令传送给从库,大大提高了复制的可用性.

  • 执行slaveof后从节点保存主节点信息
  • 从节点( slave) 内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后, 会尝试与该节点建立网络连接。
  • 从节点发送ping命令
  • 主节点进行权限验证
  • 同步数据集
  • 命令持续复制

无论是初次连接还是重新连接, 当建立一个从服务器时, 从服务器都将向主服务器发送一个 SYNC 命令。

接到 SYNC 命令的主服务器将开始执行 BGSAVE , 并在保存操作执行期间, 将所有新执行的写入命令都保存到一个缓冲区里面。

BGSAVE 执行完毕后, 主服务器将执行保存操作所得的 .rdb 文件发送给从服务器, 从服务器接收这个 .rdb 文件, 并将文件中的数据载入到内存中。

之后主服务器会以 Redis 命令协议的格式, 将写命令缓冲区中积累的所有内容都发送给从服务器。

即使有多个从服务器同时向主服务器发送 SYNC , 主服务器也只需执行一次 BGSAVE 命令, 就可以处理所有这些从服务器的同步请求。

Redis 采用了乐观复制的复制策略,允许一定时间内主从数据库的内容是不同的,但是两者的数据会最终同步.

部分重同步

从 Redis 2.8 开始, 在网络连接短暂性失效之后, 主从服务器可以尝试继续执行原有的复制进程(process), 而不一定要执行完整重同步操作。

拓扑结构

  • 一主一从
  • 一主多从
  • 树状主从

Redis 内存

Redis所有的数据都存在内存中, 当前内存虽然越来越便宜, 但跟廉价的硬盘相比成本还是比较昂贵, 因此如何高效利用Redis内存变得非常重要。 高效利用Redis内存首先需要理解Redis内存消耗在哪里, 如何管理内存, 最后才能考虑如何优化内存。

内存消耗划分

Redis进程内消耗主要包括: 自身内存+对象内存+缓冲内存+内存碎片。

对象内存是Redis内存占用最大的一块, 存储着用户所有的数据。 Redis所有的数据都采用key-value数据类型, 每次创建键值对时, 至少创建两个类型对象: key对象和value对象。 对象内存消耗可以简单理解为sizeof( keys)+sizeof( values) 。 键对象都是字符串。 value对象更复杂些, 主要包含5种基本数据类型: 字符串、 列表、 哈希、 集合、 有序集合。 其他数据类型都是建立在这5种数据结构之上实现的。

缓冲内存主要包括: 客户端缓冲、 复制积压缓冲区、 AOF缓冲区。

客户端缓冲指的是所有接入到Redis服务器TCP连接的输入输出缓冲。输入缓冲无法控制, 最大空间为1G。复制积压缓冲区: Redis在2.8版本之后提供了一个可重用的固定大小缓冲区用于实现部分复制功能, 根据repl-backlog-size参数控制, 默认1MB。 对于复制积压缓冲区整个主节点只有一个, 所有的从节点共享此缓冲区。